package com.kk.xhr.model.service.impl;

import com.kk.xhr.common.pojo.AppraiseResultEnum;
import com.kk.xhr.common.pojo.BinaryEnum;
import com.kk.xhr.model.assembler.AppraiseStructKit;
import com.kk.xhr.model.dao.AppraiseDynamicSqlSupport;
import com.kk.xhr.model.dao.AppraiseMapper;
import com.kk.xhr.model.dto.AppraiseDTO;
import com.kk.xhr.model.dto.AppraiseQueryRequestDTO;
import com.kk.xhr.model.dto.PageDto;
import com.kk.xhr.model.entity.Appraise;
import com.kk.xhr.model.service.IAppraiseService;
import lombok.RequiredArgsConstructor;
import org.mybatis.dynamic.sql.insert.render.MultiRowInsertStatementProvider;
import org.mybatis.dynamic.sql.render.RenderingStrategies;
import org.mybatis.dynamic.sql.where.AbstractWhereDSL;
import org.springframework.stereotype.Repository;

import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import static org.mybatis.dynamic.sql.SqlBuilder.insertMultiple;
import static org.mybatis.dynamic.sql.SqlBuilder.isEqualTo;
import static org.mybatis.dynamic.sql.SqlBuilder.isEqualToWhenPresent;
import static org.mybatis.dynamic.sql.SqlBuilder.isIn;

/**
 * 考评服务接口实现
 *
 * @author kkmystery
 * @version 1.0 2021/3/6
 * @since 1.0.0
 */
@Repository
@RequiredArgsConstructor
public class AppraiseServiceImpl implements IAppraiseService {
    private final AppraiseMapper appraiseMapper;
    private final AppraiseStructKit instance = AppraiseStructKit.INSTANCE;

    /**
     * {@inheritDoc}
     */
    @Override
    public Optional<AppraiseDTO> queryById(Long id) {
        return appraiseMapper.selectOne(dsl -> dsl
            .where(AppraiseDynamicSqlSupport.id, isEqualTo(id))
            .and(AppraiseDynamicSqlSupport.status, isEqualTo(BinaryEnum.TRUE.getValue())))
            .map(instance::toDto);
    }

    @Override
    public PageDto<AppraiseDTO> queryPage(AppraiseQueryRequestDTO dto) {
        long count = appraiseMapper.count(dsl -> applyQueryArgs(dsl.where(), dto));
        if (0 == count) {
            return PageDto.empty();
        }
        return new PageDto<>(count, appraiseMapper.select(dsl ->
            applyQueryArgs(dsl.where(), dto)
                .orderBy(AppraiseDynamicSqlSupport.id.descending())
                .limit(dto.getLimit())
                .offset(dto.getOffset()))
            .stream()
            .map(instance::toDto)
            .collect(Collectors.toList()));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public List<AppraiseDTO> queryByUserId(Long userId) {
        return appraiseMapper.select(dsl -> dsl
            .where(AppraiseDynamicSqlSupport.userId, isEqualTo(userId))
            .orderBy(AppraiseDynamicSqlSupport.id.descending()))
            .stream()
            .map(instance::toDto)
            .collect(Collectors.toList());
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public List<AppraiseDTO> queryNotActive(Set<Long> ids) {
        if (ids.isEmpty()) {
            return Collections.emptyList();
        }
        return appraiseMapper.select(dsl -> dsl
            .where(AppraiseDynamicSqlSupport.userId, isIn(ids))
            .and(AppraiseDynamicSqlSupport.status, isEqualTo(BinaryEnum.TRUE.getValue())))
            .stream()
            .map(instance::toDto)
            .collect(Collectors.toList());
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean add(List<Long> userIds, AppraiseDTO dto) {
        if (userIds.isEmpty()) {
            return false;
        }
        List<Appraise> appraiseList = userIds.stream()
            .distinct()
            .map(id -> instance.toEntity(dto).withUserId(id))
            .collect(Collectors.toList());
        MultiRowInsertStatementProvider<Appraise> provider = insertMultiple(appraiseList)
            .into(AppraiseDynamicSqlSupport.appraise)
            .map(AppraiseDynamicSqlSupport.userId).toProperty("userId")
            .map(AppraiseDynamicSqlSupport.appraiseDate).toProperty("appraiseDate")
            .map(AppraiseDynamicSqlSupport.content).toProperty("content")
            .map(AppraiseDynamicSqlSupport.remark).toProperty("remark")
            .build().render(RenderingStrategies.MYBATIS3);
        return userIds.size() == appraiseMapper.insertMultiple(provider);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean modify(AppraiseDTO dto) {
        if (null == dto.getId()) {
            return false;
        }
        return 1 == appraiseMapper.updateByPrimaryKeySelective(instance.toEntity(dto));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean modifyStatus(Long id, AppraiseResultEnum status) {
        if (null == status) {
            return false;
        }
        return 1 == appraiseMapper.updateByPrimaryKeySelective(new Appraise()
            .withId(id)
            .withResult(status.getValue()));
    }

    private <T extends AbstractWhereDSL> T applyQueryArgs(T where, AppraiseQueryRequestDTO dto) {
        where.and(AppraiseDynamicSqlSupport.userId, isEqualToWhenPresent(dto.getUserId()));
        if (null != dto.getResult()) {
            where.and(AppraiseDynamicSqlSupport.result, isEqualTo(dto.getResult().getValue()));
        }
        if (null != dto.getStatus()) {
            where.and(AppraiseDynamicSqlSupport.status, isEqualTo(dto.getStatus().getValue()));
        }
        return where;
    }
}
